package com.yvan.serverless.mvc;

import com.google.common.collect.Maps;
import com.yvan.platform.JsonWapper;
import com.yvan.serverless.mybatis.Sql;
import com.yvan.serverless.utils.HttpUtilExt;
import com.yvan.serverless.utils.ScriptUtils;
import lombok.Cleanup;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;

import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public class HttpRequest {
    public static final HttpRequest Instance = new HttpRequest();
    private static final String BODY_PARSED = "__BODY_PARSED__";

    private HttpRequest() {
    }

    public HttpParameterParser getHttpParameterParser() {
        return HttpParameterParser.newInstance(Objects.requireNonNull(HttpUtilExt.currentRequest()));
    }

    public Map<String, String[]> getParameters() {
        return HttpUtilExt.currentRequest().getParameterMap();
    }

    public String getRemoteIp() {
        return HttpUtilExt.currentRemoteIp();
    }

    public String getHost() {
        return HttpUtilExt.currentHost();
    }

    public String getUrl() {
        return HttpUtilExt.currentUrl();
    }

    public String getCookieValue(String name) {
        return HttpUtilExt.getCookieValue(name);
    }

    public void removeCookie(String cookieName, String path) {
        HttpUtilExt.removeCookie(cookieName, path);
    }

    public String urlEncoding(String value) {
        return HttpUtilExt.urlEncoding(value);
    }

    @SneakyThrows
    JsonWapper parseToJsonWapper() {
        HttpServletRequest request = HttpUtilExt.currentRequest();
        if (request == null) {
            return new JsonWapper();
        }

        Object jwRaw = request.getAttribute(BODY_PARSED);
        JsonWapper jw;
        if (jwRaw == null) {
            @Cleanup InputStream is = request.getInputStream();
            try {
                jw = new JsonWapper(is);
            } catch (Exception e) {
                jw = new JsonWapper();
            }
            request.setAttribute(BODY_PARSED, jw);
        } else {
            jw = (JsonWapper) jwRaw;
        }

        Map<String, Object> filter = jw.asMap("filterModel");
        Object sort = jw.get("sortModel");

        request.setAttribute(Sql.YVANUI_FILTER, filter);
        request.setAttribute(Sql.YVANUI_SORT, sort);

        return jw;
    }

    public QueryParam getQueryParam() {
        QueryParam queryParam = new QueryParam();
        queryParam.parsePageGridQuery(parseToJsonWapper());
        return queryParam;
    }

    @Getter
    @Setter
    public static class QueryParam {
        private Integer limit;
        private Integer limitOffset;
        private Boolean needCount;
        private Boolean isExportData;
        private Integer exportDataCount;
        private Map<String, Object> params = Maps.newLinkedHashMap();
        private PageDb pageDb;

        public QueryParam() {
        }

        public void parsePageGridQuery(JsonWapper jw) {
            this.limit = jw.asInt("limit");
            this.limitOffset = jw.asInt("limitOffset");
            this.needCount = jw.asBoolean("needCount");
            this.params = jw.asMap("params");
            this.isExportData = jw.asBoolean("isExportData");
            this.exportDataCount = jw.asInt("exportDataCount");

            // 如果需要计算分页
            if (this.limit >= 10000) this.limit = 10000;
            if (this.limit <= 0) this.limit = 1;
            if (this.limitOffset > 10000) this.limitOffset = 10000;
            if (this.limitOffset < 0) this.limitOffset = 0;

            //limit:10 , offset:30 = current = 30 / 10 = 3
            //limit:10 , offset:0 = current = 0 / 10 = 3
            if (isExportData == true) {
                this.limit = 10000;
                if (this.exportDataCount > 0) {
                    this.limit = exportDataCount;
                }
                this.limitOffset = 0;
            }
            int current = (this.limitOffset / this.limit) + 1;
            this.pageDb = new PageDb(current, this.limit, this.needCount);
        }

        public Map<String, Object> toNoPageDaoParam() {
            Map<String, Object> result = Maps.newHashMap();

            // 放入查询参数
            if (params != null) {
                result.putAll(params);
                result.put("isExportData", isExportData);
            }

            return result;
        }

        public Map<String, Object> toDaoParam() {
            Map<String, Object> result = toNoPageDaoParam();

            // 放入分页对象
            if (this.pageDb != null) {
                result.put("__pageDb__", this.pageDb);
            }
            return result;
        }

        /**
         * 添加数组参数
         */
        public void addParamOfList(String key, List<Object> value) {
            this.params.put(key, ScriptUtils.toList(value));
        }

        public void addParam(String key, Object value) {
            params.put(key, value);
        }

        public void addParams(Map<String, Object> param) {
            params.putAll(param);
        }

        public void removeParam(String key) {
            params.remove(key);
        }
    }

}
